package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cskaoyan.wordmemorize.converter.UserConverter;
import com.cskaoyan.wordmemorize.dao.entity.*;
import com.cskaoyan.wordmemorize.dao.mapper.*;
import com.cskaoyan.wordmemorize.dto.admin.PageDTO;
import com.cskaoyan.wordmemorize.dto.app.*;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.UserRemindCommand;
import com.cskaoyan.wordmemorize.service.UserCheckinService;
import com.cskaoyan.wordmemorize.service.UserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    UserMapper userMapper;

    @Resource
    UserCheckinMapper userCheckinMapper;
    @Autowired
    UserCheckinStatisticsMapper userCheckinStatisticsMapper;
    @Resource
    UserConverter userConverter;
    @Autowired
    LevelPrivilegeMapper levelPrivilegeMapper;
    @Autowired
    UserVocBoundStatisticsMapper userVocBoundStatisticsMapper;
    @Autowired
    UserVocBoundLogMapper userVocBoundLogMapper;
    @Autowired
    UserRemindMapper remindMapper;
    @Value("${user.remind.description}")
    String messageRemindDescription;

    @Autowired
    LevelMapper levelMapper;

    @Override
    public UserDTO getUserInfo(Long userId) {
        // 查询基本信息
        UserDO userDO = userMapper.getUserInfo(userId);
        // 查询等级对应的特权码
        return userConverter.userDO2DTO(userDO);
    }

    @Override
    public NextLevelDTO getUserNextDTO(Long userId) {

        UserDO userDO = userMapper.selectById(userId);
        if (userDO == null) {
            throw new RuntimeException("未查询到当前用户");
        }

        NextLevelDTO nextLevelDTO = new NextLevelDTO();
        // 1. 查询到用户当前的等级
        Integer levelValue = userDO.getLevelValue();
        if (levelValue == 12) {
            return null;
        }
        // 2.当前等级升到下一级所需要的签到的类型
        LambdaQueryWrapper<LevelDO> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(LevelDO::getLevelValue, levelValue + 1)
                .eq(LevelDO::getIsDeleted, 0);
        // 查询到当前等级对应升级的信息
        LevelDO levelDO = levelMapper.selectOne(lambdaQueryWrapper);
        // 根据checkInType判断签到的类型   值为1:连续签到  值为2.累计签到
        Integer checkInType = levelDO.getCheckInType();
        nextLevelDTO.setSignType(checkInType);
        // 3.下一等级剩余的天数
        //（1）查询当前的签到天数，如果等级小于6级只能累计签到（连续签到不计入等级升级的过程中）
        //（2）如果等级大于6级，判断升到6级时是如何签到的，如果是连续签到，且到6级签到之后满足连续七天的签到要求，则升级

        // 1)查表获取签到信息
        // 最近的签到的日期
        QueryWrapper<UserCheckinDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId)  // 指定用户ID
                .eq("is_deleted", 0)     // 过滤已删除记录
                .orderByDesc("sign_date") // 按签到日期>sign_date</code> 倒序排序
                .last("LIMIT 1");        // 只取第一条记录
        UserCheckinDO latestCheckin = userCheckinMapper.selectOne(queryWrapper);
        LocalDate signDate = LocalDate.now();
        if (latestCheckin != null) {
            signDate = latestCheckin.getSignDate();
        }
        // 获取签到表中记录的日期
        // 获取当前的日期
        LocalDate now = LocalDate.now();
        // 获取前一天的日期
        LocalDate today = LocalDate.now();
        LocalDate todayDate = today.minusDays(1);
        // 升级所需的总天数
        Integer checkInDays = levelDO.getCheckInDays();
        // 如果当前等级对应的签到要求为连续签到
        if (checkInType == 1) {
            // 如果签到日期为今天或者昨天，则算作累计签到
            if (now.equals(signDate) || todayDate.equals(signDate)) {
                // 查询同一签到段号
                Long stickNo = latestCheckin.getStickNo();
                LambdaQueryWrapper<UserCheckinDO> userCheckinDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
                userCheckinDOLambdaQueryWrapper.eq(UserCheckinDO::getStickNo, stickNo);
                // 已经连续签到的天数
                Long l = userCheckinMapper.selectCount(userCheckinDOLambdaQueryWrapper);
                Integer intExact = Math.toIntExact(l);
                // 升级所需的天数
                Integer needDays = checkInDays - intExact;
                nextLevelDTO.setRemainDays(needDays);
            } else {
                nextLevelDTO.setRemainDays(checkInDays);
            }
        } else if (checkInType == 2) {
            // 累计签到
            // 查询当前累计签到的天数
            LambdaQueryWrapper<UserCheckinDO> Cumulative = new LambdaQueryWrapper<>();
            Cumulative.eq(UserCheckinDO::getUserId, userId);// 筛选 user_id
            Long l = userCheckinMapper.selectCount(Cumulative);
            Integer intExact = Math.toIntExact(l);
            Integer up = checkInDays - intExact;
            nextLevelDTO.setRemainDays(up);
        }
        return nextLevelDTO;
    }


    //1. 只返回当前等级和未解锁的等级特权
    // @Override
    // public DisplayUserLevelDTO getUserLevelInfo(Long userId) {
    //     // 1.查询当前用户等级
    //     UserDO userDO = userMapper.selectById(userId);
    //     Integer userLevel = userDO.getLevelValue();
    //     if (userLevel == null) {
    //         userLevel = 0;
    //     }
    //     List<LevelDO> levelDOS = levelPrivilegeMapper.selectAllLevelWithPrivileges();
    //     List<LevelPageDTO> nowLevel = new ArrayList<>();
    //     List<LevelPageDTO> upperLevel = new ArrayList<>();
    //     for (LevelDO levelDO : levelDOS) {
    //         LevelPageDTO levelPageDTO = userConverter.levelDO2LevelPageDTO(levelDO);
    //         if (levelDO.getLevelValue().equals(userLevel)) {
    //             nowLevel.add(levelPageDTO); // 当前等级
    //         } else if (levelDO.getLevelValue() > userLevel) {
    //             upperLevel.add(levelPageDTO); // 未达到的等级
    //         }
    //     }
    //     DisplayUserLevelDTO result = new DisplayUserLevelDTO();
    //     result.setNowLevel(nowLevel);
    //     result.setUpperLevel(upperLevel);
    //     return result;
    // }


    // 2. 返回所有当前等级，包括低于当前等级的特权。以及高于当前等级的特权

    @Override
    public DisplayUserLevelDTO getUserLevelInfo(Long userId) {
        // 1.查询当前用户等级
        UserDO userDO = userMapper.selectById(userId);
        Integer userLevel = userDO.getLevelValue();
        if (userLevel == null) {
            userLevel = 0;
        }

        // 2.查询所有等级及其特权
        List<LevelDO> levelDOS = levelPrivilegeMapper.selectAllLevelWithPrivileges();

        // 3.分类当前等级(包含所有低于当前等级)和更高等级
        List<LevelPageDTO> nowLevel = new ArrayList<>();
        List<LevelPageDTO> upperLevel = new ArrayList<>();

        for (LevelDO levelDO : levelDOS) {
            LevelPageDTO levelPageDTO = userConverter.levelDO2LevelPageDTO(levelDO);
            if (levelDO.getLevelValue() <= userLevel) {
                nowLevel.add(levelPageDTO); // 当前等级及所有低于当前等级
            } else {
                upperLevel.add(levelPageDTO); // 高于当前等级
            }
        }

        // 4.返回结果
        DisplayUserLevelDTO result = new DisplayUserLevelDTO();
        result.setNowLevel(nowLevel);
        result.setUpperLevel(upperLevel);
        return result;
    }

    @Override
    public void updateVocCountOfDay(Long userId, Integer count) {
        if (userId == null || count == null || count <= 0) {
            throw new IllegalArgumentException("用户ID和计划数量不能为空，且数量必须大于0");
        }
        UpdateWrapper<UserDO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", userId)
                .eq("is_deleted", 0)
                .set("voc_count_of_day", count);
        int rows = userMapper.update(null, updateWrapper);
        if (rows == 0) {
            // 可以选择抛出异常或记录日志
            log.warn("更新用户[{}]的每日计划单词量失败，未找到该用户或用户已删除", userId);
            // 如需严格校验，可抛出异常
            // throw new UserNotFoundException("用户不存在或已删除");
        }
    }

    @Override
    public void updateUserRemind(UserRemindCommand command) {
        if (command.getUserId() == null || command.getUserId().trim().isEmpty()) {
            throw new IllegalArgumentException("用户ID不能为空");
        }
        Long userId;
        try {
            userId = Long.parseLong(command.getUserId());
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("用户ID格式错误");
        }
        LocalTime remindTime = null;
        if (command.getRemindTime() != null && !command.getRemindTime().isEmpty()) {
            try {
                remindTime = LocalTime.parse(command.getRemindTime(), DateTimeFormatter.ofPattern("HH:mm"));
            } catch (DateTimeParseException e) {
                throw new IllegalArgumentException("提醒时间格式错误，应为HH:mm");
            }
        }
        LambdaQueryWrapper<UserRemindDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserRemindDO::getUserId, userId)
                .eq(UserRemindDO::getIsDeleted, 0);
        UserRemindDO existRemind = remindMapper.selectOne(queryWrapper);
        if (existRemind != null) {
            LambdaUpdateWrapper<UserRemindDO> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserRemindDO::getId, existRemind.getId())
                    .set(remindTime != null, UserRemindDO::getRemindTime, remindTime)
                    .set(UserRemindDO::getMessageStatus, 1);
            remindMapper.update(null, updateWrapper);
        } else {

            UserRemindDO newRemind = new UserRemindDO();
            newRemind.setUserId(userId);
            newRemind.setRemindTime(remindTime);
            newRemind.setMessageStatus(1);
            newRemind.setIsDeleted(0);
            remindMapper.insert(newRemind);
        }
    }


    @Override
    public UserRemindDTO getUserRemind(Long userId) {
        return null;
    }


    @Override
    public void messageRemind() {
    }

    @Override
    public PageDTO<DisplayUserVocBoundLogDTO> getUserVocBoundLog(PageRequest pageRequest, Long userId) {
        int pageNum = pageRequest.getPageNum() == null ? 1 : pageRequest.getPageNum();
        int pageSize = pageRequest.getCount() == null ? 10 : pageRequest.getCount();
        int offset = (pageNum - 1) * pageSize;
        Long totalCount = userVocBoundLogMapper.countByUserId(userId);
        List<UserVocBoundLogDO> logDOList = userVocBoundLogMapper.selectByUserId(
                userId, offset, pageSize
        );
        List<DisplayUserVocBoundLogDTO> displayUserVocBoundLogDTOS = userConverter.userVocBoundLogDTOs2DisplayDTOs(logDOList);
        PageDTO<DisplayUserVocBoundLogDTO> displayUserVocBoundLogDTOPageDTO = new PageDTO<>();
        displayUserVocBoundLogDTOPageDTO.setPageList(displayUserVocBoundLogDTOS);
        displayUserVocBoundLogDTOPageDTO.setTotalCount(totalCount);
        return displayUserVocBoundLogDTOPageDTO;
    }

    @Override
    public UserVocBoundStatisticsDTO getUserVocBoundStatistics(Long userId) {
        LambdaQueryWrapper<UserVocBoundStatisticsDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserVocBoundStatisticsDO::getUserId, userId);
        UserVocBoundStatisticsDO userVocBoundStatisticsDO = userVocBoundStatisticsMapper.selectOne(queryWrapper);
        UserVocBoundStatisticsDTO userVocBoundStatisticsDTO = userConverter.userVocBoundStatisticsDO2DisplayDTO(userVocBoundStatisticsDO);
        return userVocBoundStatisticsDTO;
    }

    @Override
    public UserPageDTO getUserPage(Long userId) {
        UserPageDTO userPageInfo = userMapper.getUserPageInfo(userId);
        return userPageInfo;
    }

}
